﻿/// <reference path="jquery-1.7.1.js" />

//////////////////////////////////////////////////////////////////////////
// Commands definition
//////////////////////////////////////////////////////////////////////////

// Top-level command class
function ANCommand(_novel) {
	this.novel = _novel;
}
ANCommand.prototype.constructor = ANCommand;
ANCommand.prototype.onStart = function () { };
ANCommand.prototype.onClick = function () { };
ANCommand.prototype.onSkip = function () { };
ANCommand.prototype.isCompleted = function () { return true; };

//////////////////////////////////////////////////////////////////////////
// text command class
function ANCmd_text(_novel, _text, _delay) {
	ANCommand.call(this, _novel);
	this._text = _text;
	this._delay = _delay;
}
ANCmd_text.prototype = new ANCommand();
ANCmd_text.prototype.constructor = ANCmd_text;
ANCmd_text.prototype.onStart = function () {
	this.completed = false;
	this.waitCmd = undefined;

	var text = this.novel.eval(this._text);
	var delay = 100 - (this.novel.config.textSpeed != undefined ? this.novel.config.textSpeed : 50);
	if (this._delay != undefined) {
		delay = this.novel.eval(this._delay);
	}
	if (delay > 100) delay = 100;
	if (delay < 0) delay = 0;
	var textOffset = 0;

	if (text) {

		var _this = this;
		var layerText = _this.novel.layers["text"];
		var curTextArea = null;

		function charToHtml(ch) {
			if (ch == '\r') {
				ch = "";
			}
			else if (ch == '\n') {
				//var curTxt = layerText.contents().filter(function () { return this.nodeType == 3; }).text().replace(/[ \r\n\t]/gim, "");
				//var curHtml = layerText.html().replace("<!--TextTailMark-->", "").replace(/[ \r\n\t]/gim, "");
				var curTxt = layerText.text().replace(/\s/gim, "");
				var curHtml = layerText.html().replace(/<(?:[\/\s]{0,5}?)span[^<>]*>/gim, "").replace("<!--TextTailMark-->", "").trim();
				if (curTxt != ""								// Text content should not be empty
						&& /<br[^<>]*>$/i.test(curHtml) == false)	// Text content should not ends with <br> tag
				{
					ch = "<br />"
				}
				else {
					ch = "";
				}
			}

			return ch;
		}

		this.dummyTimerHandler = function (bForce) {
			if (_this.novel.script.isPaused() && !bForce) return;

			if (_this.waitCmd) {
				if (_this.waitCmd.isCompleted()) {
					//this.waitCmd = undefined;
					delete _this.waitCmd;

					// Clear current text
					var clearCmd = new ANCmd_clear(_this.novel, "true");
					clearCmd.onStart();
					delete clearCmd;
				}
			}
			else if (textOffset < text.length) {

				// Test overflow 
				if (textOffset + 1 < text.length) {
					var ch1 = charToHtml(text.charAt(textOffset));
					var ch2 = charToHtml(text.charAt(textOffset + 1));
					var $tmpElem = $("<span style='visibility:hidden'>" + ch1 + ch2 + "</span>").appendTo(curTextArea);
					if (layerText[0].clientHeight < layerText[0].scrollHeight) {
						// Execute wait command
						var waitDelay = undefined;
						//if (text.substr(0, textOffset).replace(/[ \r\n\t]/gim, "").length == 0) waitDelay = "0";
						_this.waitCmd = new ANCmd_wait(_this.novel, waitDelay);
						_this.waitCmd.onStart();
					}
					$tmpElem.hide().remove();
					if (_this.waitCmd) return;
				}

				var ch0 = charToHtml(text.charAt(textOffset++));
				if (ch0) {
					//curTextArea = layerText.children(".CurrentTextArea");
					if (curTextArea == null) {
						curTextArea = $("<span></span>")
						.appendTo(layerText)
						.css({
							color: layerText.css("color"),
							fontSize: layerText.css("fontSize"),
							lineHeight: layerText.css("lineHeight"),
							fontWeight: layerText.css("fontWeight"),
							fontFamily: layerText.css("fontFamily").replace(/['"]/g, "")
						});
					}

					curTextArea.append(ch0);
				}

			}
			else if (_this.completed == false) {
				// If end of text, then append TextTailMark
				layerText.contents().filter(function () { return this.nodeType == 8; }).remove();
				layerText.append("<!--TextTailMark-->");
				if (_this.timerForCmd != undefined) {
					clearInterval(_this.timerForCmd);
					_this.timerForCmd = undefined;
				}
				_this.completed = true;
			}
		};

		if (delay == 0 || this._propagation == true) {
			while (this.completed == false && this.waitCmd == undefined) {
				this.dummyTimerHandler();
			}
		}
		else {
			this.dummyTimerHandler();
			this.timerForCmd = setInterval(_this.dummyTimerHandler, delay);
		}
	}
	else {
		this.completed = true;
	}

};

ANCmd_text.prototype.onClick = function () {
	if (this.waitCmd) {
		this.waitCmd.onClick();
	}
	else {
		while (this.completed == false && this.waitCmd == undefined) {
			this.dummyTimerHandler(true);
		}

		var objScript = this.novel.script;
		if (this.completed
			&& objScript.curOffset + 1 < objScript.commandList.length
			&& objScript.commandList[objScript.curOffset + 1].constructor == ANCmd_text) {
			objScript.commandList[objScript.curOffset + 1]._propagation = true;
		}
	}
};
ANCmd_text.prototype.onSkip = function () {
	this.onClick();
};
ANCmd_text.prototype.isCompleted = function () {
	return this.completed;
};

//////////////////////////////////////////////////////////////////////////
// clear command class
function ANCmd_clear(_novel, _noseparator) {
	ANCommand.call(this, _novel);
	this._noseparator = _noseparator;
}
ANCmd_clear.prototype = new ANCommand();
ANCmd_clear.prototype.constructor = ANCmd_clear;
ANCmd_clear.prototype.onStart = function () {
	var noseparator = (this._noseparator ? this.novel.eval(this._noseparator) : undefined);
	var $layerText = this.novel.layers["text"];
	var $layerBackLog = this.novel.layers["backlog"];

	// Move contents to backlog layer
	while ($layerText[0].childNodes.length > 0) {
		var objNode = $layerText[0].childNodes.item(0);
		$layerText[0].removeChild(objNode);
		$layerBackLog[0].appendChild(objNode);
	}

	// Initialize text tail mark
	this.novel.layers["text"].append("<!--TextTailMark-->");

	// Draw separator
	if (noseparator !== true) {
		var objSeparator = document.createElement("hr");
		$layerBackLog[0].appendChild(objSeparator);
	}

	// Clear old logs
	while ($layerBackLog.children().length > 500) {
		$layerBackLog.children(":first").remove();
	}
};
ANCmd_clear.prototype.isCompleted = function () { return true; };



//////////////////////////////////////////////////////////////////////////
// wait command class
function ANCmd_wait(_novel, _msecDelay) {
	ANCommand.call(this, _novel);
	this._delay = _msecDelay;
};
ANCmd_wait.prototype = new ANCommand();
ANCmd_wait.prototype.constructor = ANCmd_wait;

ANCmd_wait.prototype.onStart = function () {

	this.completed = false;
	this.delay = (this._delay == undefined ? undefined : this.novel.eval(this._delay));

	// Case of waiting for user input
	if (this.delay == undefined) {
		// Remove BR tag just before
		var cmdList = this.novel.script.commandList;
		var curOffset = this.novel.script.curOffset;

		//		var $lastChild = this.novel.layers["text"].children("*:last-child");
		//		if ($lastChild != null && $lastChild.length > 0 && $lastChild[0].tagName == "BR"
		//					&& cmdList.length > curOffset + 1
		//					&& cmdList[curOffset + 1].constructor == ANCmd_clear) {
		//			$lastChild.remove();
		//			delete $lastChild;
		//		}

		//		var $contents = this.novel.layers["text"].contents();
		//		if ($contents != null && $contents.length >= 2
		//			&& $contents[$contents.length - 1].nodeType == 8
		//			&& $contents[$contents.length - 2].tagName == "BR"
		//			&& cmdList.length > curOffset + 1
		//			&& cmdList[curOffset + 1].constructor == ANCmd_clear) {
		//			$($contents[$contents.length - 2]).remove();
		//		}

		var $lastChild = this.novel.layers["text"].children(":last").children(":last");
		if ($lastChild.length > 0 
			&& $lastChild[0].tagName == "BR"
			&& cmdList.length > curOffset + 1
			&& cmdList[curOffset + 1].constructor == ANCmd_clear) 
		{
			$lastChild.remove();
		}



		// show waiting mark
		this.markOpacity = 1.0;
		this.markOpacityAcc = -0.04;
		this.objMark = $("<span></span>")
							.appendTo(this.novel.layers["text"])
							.html('&nbsp;' + String.fromCharCode(9660))		// "▼";
							.css({
								color: "inherit",
								fontWeight: "inherit",
								fontFamily: "inherit",
								fontSize: "inherit"
							});

		if ($.browser.msie) {
			this.objMark.css("position", "absolute");
		}

		var _this = this;
		blinkMark = function () {
			if (_this.completed) return;
			_this.objMark.fadeToggle(600, blinkMark);
		}
		blinkMark();

	}
	// Case of waiting specific time
	else {
		this.startTime = (new Date()).getTime();
	}
};

ANCmd_wait.prototype.onClick = function () {
	if (this.delay == undefined) {
		this.objMark.remove();
		this.completed = true;
	}
};

ANCmd_wait.prototype.onSkip = function () {
	if (this.delay == undefined) {
		this.onClick();
	}
	else {
		this.delay = 0;
	}
};

ANCmd_wait.prototype.isCompleted = function () {
	if (this.delay != undefined 
		&& (new Date()).getTime() - this.startTime > this.delay) {
		this.completed = true;
	}

	return this.completed;
};


//////////////////////////////////////////////////////////////////////////
// bg command class
function ANCmd_bg(_novel, _src, _delay, _type) {
	ANCommand.call(this, _novel);
	this.startTime = null;
	this.dummyLayer = null;
	this._src = _src;
	this._delay = _delay;
	this._type = _type;
}
ANCmd_bg.prototype = new ANCommand();
ANCmd_bg.prototype.constructor = ANCmd_bg;

ANCmd_bg.prototype.onStart = function () {

	this.completed = false;
	this.src = (this._src ? this.novel.eval(this._src) : undefined);
	var delay = (this._delay ? this.novel.eval(this._delay) : 1000);
	var type = (this._type ? this.novel.eval(this._type) : 0);
	var _this = this;
	this.novel.setBG(this.src, delay, type, function () { _this.completed = true; });
	this.startTime = (new Date()).getTime();
};

ANCmd_bg.prototype.isCompleted = function () {
	if (this.completed == false
		&& this.startTime + 500 < (new Date()).getTime()
		&& this.novel.layers["bg"].children("._AN_BGIMG").length > 0
		&& this.src
	) {
		this.novel.layers["bg"].children("._AN_BGIMG")[0].src = this.src;
	}
	return this.completed;
};


//////////////////////////////////////////////////////////////////////////
// setimg command class
function ANCmd_setimg(_novel, _id, _url, _parentLayerId, _delay) {
	ANCommand.call(this, _novel);
	this._id = _id;
	this._url = _url;
	this._parentLayerId = _parentLayerId;
	this._delay = _delay;
}
ANCmd_setimg.prototype = new ANCommand();
ANCmd_setimg.prototype.constructor = ANCmd_setimg;
ANCmd_setimg.prototype.onStart = function () {

	this.id = (this._id ? this.novel.eval(this._id) : null);
	this.url = (this._url ? this.novel.eval(this._url) : null);
	this.completed = false;

	var _this = this;
	var parentLayerId = (this._parentLayerId ? this.novel.eval(this._parentLayerId) : null);
	var delay = (this._delay ? this.novel.eval(this._delay) : 0);
	var prevImg = this.novel.images[this.id];
	if (prevImg != undefined) prevImg = prevImg[0];

	if (!this.novel.layers[parentLayerId]) parentLayerId = "ch";

	// If image id exists
	if (prevImg != undefined) {

		// Clear existing one
		function clearExistingImg() {
			$(prevImg).hide(delay, function () {
				_this.completed = true;
				$(this).remove();
			});
		}

		// In case of changing
		if (this.url) {

			// Stop animation of the previous img
			$(prevImg).stop(true, true);

			// Create new img element on the parent layer
			this.novel.images[this.id] = $("<img>");
			this.novel.images[this.id].appendTo(this.novel.layers[parentLayerId]);
			this.novel.images[this.id].data("parentLayerId", parentLayerId);
			this.novel.images[this.id].css({
				position: "absolute",
				padding: 0,
				margin: 0,
				backgroundColor: "",
				left: $(prevImg).css("left"),
				top: $(prevImg).css("top"),
				opacity: 0
			});
			this.novel.images[this.id].load(function () {
				//$(this).data("loadCompleted", true);
				$(this).animate({ opacity: $(prevImg).css("opacity") }, delay);
				clearExistingImg();
			});
			this.novel.images[this.id].error(function () {
				//$(this).data("loadCompleted", true);
				//clearExistingImg();
				_this.completed = true;
			});
			this.novel.images[this.id].data("isNeverShown", $(prevImg).data("isNeverShown"));
			this.novel.images[this.id].attr("src", this.url);


		}
		// Simply Clear existing one
		else {
			this.novel.images[this.id] = undefined;
			delete this.novel.images[this.id];
			clearExistingImg();
		}
	}
	// Set new image using the given url
	else {

		// Create img element on the parent layer
		this.novel.images[this.id] = $("<img>")
			.appendTo(this.novel.layers[parentLayerId])
			.data("parentLayerId", parentLayerId)
		//.data("loadCompleted", false)
			.load(function () {
				//$(this).data("loadCompleted", true);
				_this.completed = true;
			})
			.error(function () {
				//$(this).data("loadCompleted", true);
				_this.completed = true;
			})
			.attr("src", this.url)
			.data("isNeverShown", true)
			.css({
				position: "absolute",
				padding: 0,
				margin: 0,
				backgroundColor: "",
				left: "",
				top: "",
				opacity: 0
			});
		//this.novel.images[this.id].loadCompleted = false;
	}
};
ANCmd_setimg.prototype.isCompleted = function () {
	
	//if (!this.url) return true;	// Without image url, it always returns 'completed'.
	
	//try {
	//	if (this.novel.images[this.id].data("loadCompleted") === false) return false;
	//} catch (e) { }
	//return true;
	return this.completed;
};


//////////////////////////////////////////////////////////////////////////
// img command class
function ANCmd_img(_novel, _id, _delay, _x, _y, _opacity) {
	ANCommand.call(this, _novel);
	this._id = _id;
	this._delay = _delay;
	this._x = _x;
	this._y = _y;
	this._opacity = _opacity;
}
ANCmd_img.prototype = new ANCommand();
ANCmd_img.prototype.constructor = ANCmd_img;
ANCmd_img.prototype.onStart = function () {

	this.completed = false;
	var imgId = this.novel.eval(this._id);
	var delay = (this._delay ? this.novel.eval(this._delay) : 0);
	var destX = (this._x && this._x != "auto" ? this.novel.eval(this._x) : undefined);
	var destY = (this._y && this._y != "auto" ? this.novel.eval(this._y) : undefined);
	var destOpacity = (this._opacity ? this.novel.eval(this._opacity) : undefined);

	this.img = this.novel.images[imgId];
	if (this.img) {

		if (this.img.data("isNeverShown") && destX != undefined)
			this.img.css("left", destX);
		if (this.img.data("isNeverShown") && destY != undefined)
			this.img.css("top", destY);
		if (this.img.css("opacity") == undefined)
			this.img.css("opacity", 0);

		var cssSet = {};
		if (destX != undefined) cssSet["left"] = destX;
		if (destY != undefined) cssSet["top"] = destY;
		if (destOpacity != undefined) cssSet["opacity"] = destOpacity;
		this.img.data("isNeverShown", false);
		var _this = this;
		this.img.animate(cssSet, delay, function () { _this.completed = true; });
	}
	else {
		this.completed = true;
	}
};
ANCmd_img.prototype.isCompleted = function () { return this.completed; };


//////////////////////////////////////////////////////////////////////////
// inline-javascript command class
function ANCmd_javascript(_novel, _jscript) {
	ANCommand.call(this, _novel);
	this.completed = false;
	this._jscript = _jscript;
}
ANCmd_javascript.prototype = new ANCommand();
ANCmd_javascript.prototype.constructor = ANCmd_javascript;
ANCmd_javascript.prototype.onStart = function () {

	this.completed = false;

	try {
		//this.jscript = eval(this._jscript);
		this.novel.eval(this._jscript);
	} catch (ex) {

	}

	this.completed = true;
};
ANCmd_javascript.prototype.isCompleted = function () { return this.completed; };


//////////////////////////////////////////////////////////////////////////
// initchoice command class
function ANCmd_initchoice(_novel) {
	ANCommand.call(this, _novel);
}
ANCmd_initchoice.prototype = new ANCommand();
ANCmd_initchoice.prototype.constructor = ANCmd_initchoice;
ANCmd_initchoice.prototype.onStart = function () {
	this.novel.isChoiceMode = true;
	this.completed = true;
};
ANCmd_initchoice.prototype.isCompleted = function () { return this.completed; };


//////////////////////////////////////////////////////////////////////////
// waitchoice command class
function ANCmd_waitchoice(_novel) {
	ANCommand.call(this, _novel);
}
ANCmd_waitchoice.prototype = new ANCommand();
ANCmd_waitchoice.prototype.constructor = ANCmd_waitchoice;
ANCmd_waitchoice.prototype.isCompleted = function () { return (this.novel.isChoiceMode === false); };


//////////////////////////////////////////////////////////////////////////
// textbutton command class
function ANCmd_textbutton(_novel, _id, _text, _url, _part, _x, _y, _width, _height) {
	ANCommand.call(this, _novel);
	this._id = _id;
	this._text = _text;
	this._url = _url;
	this._part = _part;
	this._x = _x;
	this._y = _y;
	this._width = _width;
	this._height = _height;
}
ANCmd_textbutton.prototype = new ANCommand();
ANCmd_textbutton.prototype.constructor = ANCmd_textbutton;
ANCmd_textbutton.prototype.onStart = function () {
	var _novel = this.novel;

	this.id = _novel.eval(this._id);
	this.text = (this._text ? _novel.eval(this._text) : undefined);
	this.url = (this._url ? _novel.eval(this._url) : undefined);
	this.part = (this._part ? _novel.eval(this._part) : "");
	this.x = (this._x ? _novel.eval(this._x) : undefined);
	this.y = (this._y ? _novel.eval(this._y) : undefined);
	this.width = (this._width ? _novel.eval(this._width) : undefined);
	this.height = (this._height ? _novel.eval(this._height) : undefined);

	// Remove existing textbutton of the id
	if (_novel.buttons[this.id]) {
		_novel.buttons[this.id].remove();
		_novel.buttons[this.id] = undefined;
	}

	// Set button using the given text and url
	if (this.text && this.url) {
		// Create img element on the parent layer
		var elemBtn = $("<div></div>").css({
			padding: 0,
			margin: 0,
			width: this.width,
			height: this.height,
			cursor: "pointer"
		});

		// Click Handler
		elemBtn.data("isChoiceButton", _novel.isChoiceMode);
		elemBtn.data("url", this.url);
		elemBtn.data("part", this.part);
		elemBtn.click(function () {
			_novel.script.jump($(this).data("url"), $(this).data("part"));
			if ($(this).data("isChoiceButton") == true) {
				_novel.clearChoiceButtons(); // Clear other choice buttons
				_novel.isChoiceMode = false; // Disable Choice Mode
			}
			return false;
		});

		// check x,y position was given or not
		var textLayer = _novel.layers["text"];
		if (this.x && this.y) {
			elemBtn.appendTo(_novel.layers["btn"])
					.css({
						position: "absolute",
						left: this.x,
						top: this.y,
						color: textLayer.css("color"),
						fontWeight: textLayer.css("fontWeight"),
						fontFamily: textLayer.css("fontFamily"),
						fontSize: textLayer.css("fontSize"),
						textShadow: ($.browser.msie ? "" : textLayer.css("textShadow"))
					})
					.html(this.text);
		}
		else {
			elemBtn.appendTo(_novel.layers["btncenter"])
					.css({
						position: "relative",
						margin: 10,
						height: 45
					})
					.hover(
						function () {
							$(this).children("div[name=buttonText]").css({ paddingLeft: "2px", paddingTop: "4px" });
							if(!$.browser.msie) $(this).css("opacity", 1);
						},
						function () {
							$(this).children("div[name=buttonText]").css({ paddingLeft: "4px", paddingTop: "6px" });
							if (!$.browser.msie) $(this).css("opacity", 0.9);
						}
					);

			if ($.browser.msie) {
				elemBtn.append($("<div class='choiceTextButtonBackgroundLeft' style='left:0;width:15%;height:100%;position:absolute;'></div>"))
						.append($("<div class='choiceTextButtonBackgroundCenter' style='left:15%;width:70%;height:100%;position:absolute;'></div>"))
						.append($("<div class='choiceTextButtonBackgroundRight' style='left:85%;width:15%;height:100%;position:absolute;'></div>"));
			}
			else {
				elemBtn.append($("<div class='choiceTextButtonBackground' style='width:100%;height:100%;position:absolute;'></div>"));
			}
			elemBtn.append(
						$("<div></div>").css({
							left: 0,
							width: "100%",
							height: "100%",
							position: "absolute",
							zIndex: 10,
							color: textLayer.css("color"),
							fontWeight: textLayer.css("fontWeight"),
							fontFamily: textLayer.css("fontFamily"),
							fontSize: textLayer.css("fontSize"),
							paddingLeft: "4px",
							paddingTop: "6px",
							textShadow: ($.browser.msie ? "" : textLayer.css("textShadow"))
						})
						.attr("name", "buttonText")
						.html(this.text)
			);

			var btncenterLayer = _novel.layers["btncenter"];
			btncenterLayer.css("marginLeft", -btncenterLayer.outerWidth() / 2);
			btncenterLayer.css("marginTop", -btncenterLayer.outerHeight() / 2);
		}

		// Add the element to 
		elemBtn.data("command", this);
		_novel.buttons[this.id] = elemBtn;
	}
};
ANCmd_textbutton.prototype.isCompleted = function () { return true; };

//////////////////////////////////////////////////////////////////////////
// bgm command class
function ANCmd_bgm(_novel, _url, _delay) {
	ANCommand.call(this, _novel);
	this._url = _url;
	this._delay = _delay;
}
ANCmd_bgm.prototype = new ANCommand();
ANCmd_bgm.prototype.constructor = ANCmd_bgm;
ANCmd_bgm.prototype.onStart = function () {
	this.completed = false;
	this.url = (this._url ? this.novel.eval(this._url) : null);
	var delay = (this._delay ? this.novel.eval(this._delay) : 0);

	// Play new BGM
	if (this.url != null) {
		this.novel.bgm.play(this.url);
		this.completed = true;
	}
	else {
		if (delay > 0) {
			var _this = this;
			var startVol = _this.novel.bgm.getVolume();
			var startTime = (new Date()).getTime(); // Set startTime to now
			var dummyTimerHandler = function () {
				var deltaRatio = ((new Date()).getTime() - startTime) / delay;
				if (deltaRatio < 1) {
					var vol = startVol * (1 - deltaRatio);
					if (vol < 0) vol = 0;
					_this.novel.bgm.setVolume(vol);
				}
				else if (!_this.completed) {
					_this.novel.bgm.stop(); 				// Stop BGM
					_this.novel.bgm.setVolume(startVol); // Restore volume
					_this.completed = true;
					clearInterval(_this.timerForCmd);
					_this.timerForCmd = undefined;
				}
			};
			_this.timerForCmd = setInterval(dummyTimerHandler, 50);
		}
		else {
			this.novel.bgm.stop(); 	// Stop BGM right now
			this.completed = true;
		}
	}

};
ANCmd_bgm.prototype.isCompleted = function () { return this.completed; };


//////////////////////////////////////////////////////////////////////////
// bgmstop command class
function ANCmd_bgmstop(_novel, _delay) {
	ANCommand.call(this, _novel);
	this._delay = _delay;
}
ANCmd_bgmstop.prototype = new ANCommand();
ANCmd_bgmstop.prototype.constructor = ANCmd_bgmstop;
ANCmd_bgmstop.prototype.onStart = function () {
	this.completed = false;
	var delay = (this._delay ? this.novel.eval(this._delay) : 0);

	if (delay > 0) {
		var _this = this;
		var startVol = _this.novel.bgm.getVolume();
		var startTime = (new Date()).getTime(); // Set startTime to now
		var dummyTimerHandler = function () {
			var deltaRatio = ((new Date()).getTime() - startTime) / delay;
			if (deltaRatio < 1) {
				var vol = startVol * (1 - deltaRatio);
				if (vol < 0) vol = 0;
				_this.novel.bgm.setVolume(vol);
			}
			else if (!_this.completed) {
				_this.novel.bgm.stop(); 				// Stop BGM
				_this.novel.bgm.setVolume(startVol);	// Restore volume
				_this.completed = true;
				clearInterval(_this.timerForCmd);
				_this.timerForCmd = undefined;
			}
		};
		_this.timerForCmd = setInterval(dummyTimerHandler, 50);
	}
	else {
		this.novel.bgm.stop(); 	// Stop BGM right now
		this.completed = true;
	}
};
ANCmd_bgmstop.prototype.isCompleted = function () { return this.completed; };

/*
//////////////////////////////////////////////////////////////////////////
// padding command class
function ANCmd_padding(_novel, _textboxPadding) {
	ANCommand.call(this, _novel);
	this._textboxPadding = _textboxPadding;
}
ANCmd_padding.prototype = new ANCommand();
ANCmd_padding.prototype.constructor = ANCmd_padding;
ANCmd_padding.prototype.onStart = function () {
	if (!this._textboxPadding) return;
	var textboxPadding = this.novel.eval(this._textboxPadding);
	if (textboxPadding == undefined) return;

	this.novel.textboxPadding = textboxPadding;
	this.novel.adjustLayerSizes();
};
ANCmd_padding.prototype.isCompleted = function () { return true; };

//////////////////////////////////////////////////////////////////////////
// margin command class
function ANCmd_margin(_novel, _textboxMargin) {
	ANCommand.call(this, _novel);
	this._textboxMargin = _textboxMargin;
}
ANCmd_margin.prototype = new ANCommand();
ANCmd_margin.prototype.constructor = ANCmd_margin;
ANCmd_margin.prototype.onStart = function () {
	if (!this._textboxMargin) return;
	var textboxMargin = this.novel.eval(this._textboxMargin);
	if (textboxMargin == undefined) return;

	this.novel.textboxMargin = textboxMargin;
	this.novel.adjustLayerSizes();
};
ANCmd_margin.prototype.isCompleted = function () { return true; };
*/

//////////////////////////////////////////////////////////////////////////
// textbox command class
function ANCmd_textbox(_novel, _x, _y, _width, _height, _color, _opacity, _textboxPadding) {
	ANCommand.call(this, _novel);
	this._x = _x;
	this._y = _y;
	this._width = _width;
	this._height = _height;
	this._color = _color;
	this._opacity = _opacity;
	this._textboxPadding = _textboxPadding;
}
ANCmd_textbox.prototype = new ANCommand();
ANCmd_textbox.prototype.constructor = ANCmd_textbox;
ANCmd_textbox.prototype.onStart = function () {
	var $textbgLayer = this.novel.layers["textbg"];
	var $textLayer = this.novel.layers["text"];
	var $viewport = $(this.novel.viewportElement);

	// Text box margin
	if (this._x != undefined || this._y != undefined || this._width != undefined || this._height != undefined) {
		var x = (this._x == undefined) ? $textbgLayer.position().left : this.novel.eval(this._x);
		var y = (this._y == undefined) ? $textbgLayer.position().top : this.novel.eval(this._y);
		var width = (this._width == undefined) ? $textbgLayer.width() : this.novel.eval(this._width);
		var height = (this._height == undefined) ? $textbgLayer.height() : this.novel.eval(this._height);
		this.novel.textboxMargin = y + "px "
								+ ($viewport.width() - x - width) + "px "
								+ ($viewport.height() - y - height) + "px "
								+ x + "px";
	}

	// Text box padding
	if (this._textboxPadding != undefined) {
		var textboxPadding = this.novel.eval(this._textboxPadding);
		if (textboxPadding != undefined) this.novel.textboxPadding = textboxPadding;
	}

	// Text box background color
	if (this._color != undefined) {
		var color = this.novel.eval(this._color);
		if (color != undefined) {
			if (/^#/.test(color)) {
				$textbgLayer.css("backgroundImage", "none");
				$textbgLayer.css("backgroundColor", color);
			}
			else {
				$textbgLayer.css("backgroundColor", "transparent");
				$textbgLayer.css("backgroundImage", "url(" + color + ")");
			}
		}
	}

	// Text box opacity
	if (this._opacity != undefined) {
		var opacity = this.novel.eval(this._opacity);
		if (opacity != undefined) $textbgLayer.css("opacity", opacity);
	}

	this.novel.adjustLayerSizes();
};
ANCmd_textbox.prototype.isCompleted = function () { return true; };


//////////////////////////////////////////////////////////////////////////
// jump command class
function ANCmd_jump(_novel, _url, _part) {
	ANCommand.call(this, _novel);
	this._url = _url;
	this._part = _part;
}
ANCmd_jump.prototype = new ANCommand();
ANCmd_jump.prototype.constructor = ANCmd_jump;
ANCmd_jump.prototype.onStart = function () {
	var url = (this._url ? this.novel.eval(this._url) : null);
	var part = (this._part ? this.novel.eval(this._part) : null);
	var _this = this;
	this.completed = false;
	this.novel.script.jump(url, part, function () { _this.completed = true; });
};
ANCmd_jump.prototype.isCompleted = function () { return this.completed; };



//////////////////////////////////////////////////////////////////////////
// save command class
function ANCmd_save(_novel) {
	ANCommand.call(this, _novel);
}
ANCmd_save.prototype = new ANCommand();
ANCmd_save.prototype.constructor = ANCmd_save;
ANCmd_save.prototype.onStart = function () {
	this.novel.sysmenu.showSaveScreen(true);
};
ANCmd_save.prototype.isCompleted = function () { return true; };

//////////////////////////////////////////////////////////////////////////
// load command class
function ANCmd_load(_novel) {
	ANCommand.call(this, _novel);
}
ANCmd_load.prototype = new ANCommand();
ANCmd_load.prototype.constructor = ANCmd_load;
ANCmd_load.prototype.onStart = function () {
	this.novel.sysmenu.showLoadScreen(true);
};
ANCmd_load.prototype.isCompleted = function () { return true; };


//////////////////////////////////////////////////////////////////////////
// new command class
function ANCmd_new(_novel) {
	ANCommand.call(this, _novel);
}
ANCmd_new.prototype = new ANCommand();
ANCmd_new.prototype.constructor = ANCmd_new;
ANCmd_new.prototype.onStart = function () {
	this.novel.newGame();
};
ANCmd_new.prototype.isCompleted = function () { return true; };


//////////////////////////////////////////////////////////////////////////
// config command class
function ANCmd_config(_novel) {
	ANCommand.call(this, _novel);
}
ANCmd_config.prototype = new ANCommand();
ANCmd_config.prototype.constructor = ANCmd_config;
ANCmd_config.prototype.onStart = function () {
	this.novel.sysmenu.showConfigScreen(true);
};
ANCmd_config.prototype.isCompleted = function () { return true; };



//////////////////////////////////////////////////////////////////////////
// enable command class
function ANCmd_enable(_novel, _cleanMode, _backlogMode, _sysmenuMode) {
	ANCommand.call(this, _novel);
	this._cleanMode = _cleanMode;
	this._backlogMode = _backlogMode;
	this._sysmenuMode = _sysmenuMode;
}
ANCmd_enable.prototype = new ANCommand();
ANCmd_enable.prototype.constructor = ANCmd_enable;
ANCmd_enable.prototype.onStart = function () {
	var cleanMode = (this._cleanMode ? this.novel.eval(this._cleanMode) : undefined);
	var backlogMode = (this._backlogMode ? this.novel.eval(this._backlogMode) : undefined);
	var sysmenuMode = (this._sysmenuMode ? this.novel.eval(this._sysmenuMode) : undefined);
	this.novel.enableFunctionalities(cleanMode, backlogMode, sysmenuMode);
};
ANCmd_enable.prototype.isCompleted = function () { return true; };


//////////////////////////////////////////////////////////////////////////
// font command class
function ANCmd_font(_novel, _color, _size, _weight, _family) {
	ANCommand.call(this, _novel);
	this._color = _color;
	this._size = _size;
	this._weight = _weight;
	this._family = _family;
}
ANCmd_font.prototype = new ANCommand();
ANCmd_font.prototype.constructor = ANCmd_font;
ANCmd_font.prototype.onStart = function () {
	var color = (this._color ? this.novel.eval(this._color) : undefined);
	var size = (this._size ? this.novel.eval(this._size) : undefined);
	var weight = (this._weight ? this.novel.eval(this._weight) : undefined);
	var family = (this._family ? this.novel.eval(this._family) : undefined);
	var layerText = this.novel.layers["text"];
	//var curTextArea = layerText.children(".CurrentTextArea");

	if (color) layerText.css("color", color);
	if (size) {
		layerText.css("fontSize", size);
		layerText.css("lineHeight", Math.round(eval(size) * 1.3) + "px");
	}
	if (weight) layerText.css("fontWeight", weight);
	if (family) layerText.css("fontFamily", family);

	/*
	curTextArea.removeClass("CurrentTextArea");
	curTextArea = $("<span class='CurrentTextArea'></span>")
	.appendTo(layerText)
	.css({
	//backgroundColor: "yellow",
	color: layerText.css("color"),
	fontSize: layerText.css("fontSize"),
	fontWeight: layerText.css("fontWeight"),
	fontFamily: layerText.css("fontFamily").replace(/['"]/g, "")
	});
	layerText.contents().filter(function () { return this.nodeType == 8; }).remove();
	layerText.append("<!--TextTailMark-->");
	*/
};
ANCmd_font.prototype.isCompleted = function () { return true; };



//////////////////////////////////////////////////////////////////////////
// end command class
function ANCmd_end(_novel) {
	ANCommand.call(this, _novel);
}
ANCmd_end.prototype = new ANCommand();
ANCmd_end.prototype.constructor = ANCmd_end;
//ANCmd_end.prototype.onStart = function () { };
//ANCmd_end.prototype.onClick = function () { };
//ANCmd_end.prototype.onSkip = function () { };
ANCmd_end.prototype.isCompleted = function () { return false; };

//